﻿using System;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;

namespace System.Collections.Generic
{
	public static class RangeEnumerableExtensions
	{

		public static IEnumerable<Range> SplitInRanges( this IEnumerable<int> values )
		{
			return values.SplitInRanges( 1 );
		}

		public static IEnumerable<Range> SplitInRanges( this IEnumerable<int> values, int step )
		{
			if ( values != null && step > 0 )
			{
				var iterator = values.GetEnumerator();
				int count = 0;
				int min = 0;
				int max = 0;

				while ( iterator.MoveNext() )
				{
					if ( count > 0 )
					{
						int interval = iterator.Current - max;

						if ( interval < 0 )
							throw new InvalidOperationException( "Os valores não estão ordenados para serem divididos em intervalos." );
						else if ( interval <= step )
							max = iterator.Current;
						else
						{
							yield return new Range( min, max, count );

							count = 0;
							min = max = iterator.Current;
						}
					}
					else  // if ( count == 0 )
						min = max = iterator.Current;

					count++;
				}

				if ( count > 0 )
					yield return new Range( min, max, count );
			}
		}

	}


	/// <summary>
	/// Representa um intervalo da coleção
	/// </summary>
	public sealed class Range
	{

		/// <summary>
		/// 
		/// </summary>
		/// <param name="min"></param>
		/// <param name="max"></param>
		/// <param name="count"></param>
		public Range( int min, int max, int count )
		{
			this.Min = min;
			this.Max = max;
			this.Count = count;
		}

		/// <summary>
		/// Obtém o valor mínimo do intervalo
		/// </summary>
		public int Min
		{ get; private set; }

		/// <summary>
		/// Obtém o valor máximo do intervalo
		/// </summary>
		public int Max
		{ get; private set; }

		/// <summary>
		/// Obtém quantos valores foram encontrados entre esses valores
		/// </summary>
		public int Count
		{ get; private set; }


		/// <summary>
		/// 
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public bool IsInRange( int value )
		{
			return this.Min <= value && value <= this.Max;
		}
	}
}
